#include<iostream>
#include<string>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>

#define LISTEN_MAX 5
class Tcpsocket{
    private:
        int _sockfd;
    public:
        Tcpsocket():_sockfd(-1){}
        Tcpsocket(int fd):_sockfd(fd){}

        ~Tcpsocket() {/*Close();*/}
        bool Available(){return _sockfd!=-1;}
        int Fd(){return _sockfd;}
        bool Socket(){
            _sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(_sockfd<0){
                perror("socket error");
                return false;
            }
            return true;
        }
        bool Bind(const std::string &ip,uint16_t port){
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            addr.sin_addr.s_addr = inet_addr(ip.c_str());
            socklen_t len = sizeof(struct sockaddr_in);
            int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
            if(ret<0){
                perror("bind error");
                return false;
            }
            return true;
        }
        bool Listen(int backlog = LISTEN_MAX){
            int ret = listen(_sockfd,backlog);
            if(ret<0){
                perror("listen error");
                return false;
            }
            return true;
        }
        Tcpsocket Accept(std::string *peer_ip = NULL,uint16_t *peer_port = NULL){
            struct sockaddr_in addr;
            socklen_t len = sizeof(struct sockaddr_in);
            Tcpsocket new_socket;
            int newfd = accept(_sockfd,(struct sockaddr*)&addr,&len);
            if(newfd<0){
                perror("accept error");
                return new_socket;
            }
            new_socket._sockfd = newfd;
            if(peer_ip!=NULL)*peer_ip = inet_ntoa(addr.sin_addr);
            if(peer_port!=NULL)*peer_port = ntohs(addr.sin_port);
            return new_socket;
        }
        std::string getline(){
            char ch;
            std::string res;
            while(1){
                int ret = recv(_sockfd,&ch,1,0);
                if(ret<=0){
                    return res;
                }
                if(ch == '\n'){
                    res.append(1,ch);
                }
            }
        }
        bool Recv(std::string *body,size_t len = 4096){
            body->resize(len);
            ssize_t ret = recv(_sockfd,&(*body)[0],len,0);
            if(ret<0){
                perror("recv error");
                return false;
            }else if(ret == 0){
                printf("connection shutdown");
                return false;
            }
            body->resize(ret);
            return true;
        }
        bool Send(const std::string &body){
            int slen = 0;
            while(slen<body.size()){
                ssize_t ret = send(_sockfd,body.c_str()+slen,body.size(),0);
                if(ret<0){
                    perror("send error");
                    return false;
                }
                slen+=ret;
            } 
            return true;
        }
        bool Connect(const std::string &ip,uint16_t port){
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            addr.sin_addr.s_addr = inet_addr(ip.c_str());
            socklen_t len = sizeof(struct sockaddr_in);
            int ret = connect(_sockfd,(struct sockaddr*)&addr,len);
            if(ret<0){
                perror("Connect error");
                return false;
            }
            return true;
        }
        bool Close(){
            if(_sockfd<0){
                return false;
            }
            close(_sockfd);
            _sockfd = -1;
            return true;
        }
};